package com.luckdraw.service.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.nutz.http.Header;
import org.nutz.http.Http;
import org.nutz.http.Response;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Xmls;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import com.luckdraw.domain.WithdrawalLog;
import com.luckdraw.service.TenpayService;
import com.luckdraw.util.Constant;
import com.luckdraw.util.CreateOrderNum;
import com.luckdraw.util.GetUUID;
import com.luckdraw.util.TenpayUtil;

@IocBean
public class TenpayServiceImpl implements TenpayService {
	
	@Inject("java:$conf.get('tenpay.appId')")
	private String appId;
	
	@Inject("java:$conf.get('tenpay.mchId')")
	private String mchId;

	@Inject("java:$conf.get('tenpay.apiKey')")
	private String apiKey;
	
	@Inject("java:$conf.get('tenpay.notifyUrl')")
	private String notifyUrl;
	
	@Inject("java:$conf.get('tenpay.unifiedorder')")
	private String unifiedorder;
	
	private static Log log = Logs.getLog("PayMobule");
	
	/**
	 * 微信下单
	 * @param body	商品描述
	 * @param detail	商品详情
	 * @param out_trade_no	商户订单号
	 * @param total_fee	支付金额
	 * @param spbill_create_ip	客户端IP
	 * @param openId	微信用户openid
	 * @return
	 */
	public String unifiedOrder(String body,String detail,String out_trade_no,String total_fee,String spbill_create_ip,String openId) {
		Map<String,String> params = new HashMap<String, String>();
		params.put("appid", appId);//公众账号id
		params.put("mch_id", mchId);//商户号
		params.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));//随机数
		params.put("body", body);//商品描述
		params.put("detail", detail);//商品详情
		params.put("out_trade_no", out_trade_no);//商户订单号
		params.put("total_fee", total_fee);//订单总金额
		params.put("spbill_create_ip", spbill_create_ip);//终端IP
		params.put("openid", openId);
		params.put("notify_url", notifyUrl);//通知地址
		params.put("trade_type", "JSAPI");
		String entity = TenpayUtil.paramsToXml(params, apiKey);
		Response response = Http.post3(unifiedorder, entity, Header.create().asFormContentType("application/xml"), 60000);
		if(response.isOK()){
			String respStr = response.getContent();
			System.out.println(respStr);
			log.info("unifiedOrder|weixinResponse:"+respStr);
			try{
				NutMap respMap = Xmls.xmlToMap(respStr);
				if(respMap!=null&&respMap.size()>0){
					if("SUCCESS".equals(respMap.getString("return_code"))&&"SUCCESS".equals(respMap.getString("return_code"))){
						return respMap.getString("prepay_id");
					}
				}
			}catch(Exception e){
				log.info("unifiedOrder|Exception:"+e.getLocalizedMessage());
			}
		}
		return "";
	}
	
	/**
	 * 生成jsapi支付请求信息
	 * @param prepayId 微信预支付订单ID
	 * @return
	 */
	public NutMap getJsPayRequestInfo(String prepayId){
		NutMap map = new NutMap();
		map.put("appId", appId);
		map.put("timeStamp", new Date().getTime());
		map.put("nonceStr", UUID.randomUUID().toString().replaceAll("-", ""));
		map.put("package", "prepay_id="+prepayId);
		map.put("signType", "MD5");
		map.put("paySign", TenpayUtil.genPackageSign(TenpayUtil.toSortedMap(map), apiKey));
		return map;
	}
	
	/**
	 * 提现
	 * @param openid
	 * @param momney
	 * @return
	 */
	public WithdrawalLog withdrawals(String openid,int momney){
		WithdrawalLog wLog = new WithdrawalLog();
		wLog.setOpenId(openid);
		wLog.setAmount(momney);
		wLog.setCrateTime(new Date());
		String return_code = "";
		String result_code = "";
		String err_code = "";
		try {
			wLog.setWithdrawalType(WithdrawalLog.WITHDRAWAL_TYPE_REDPACK);
			NutMap map = sendredpack(openid,momney);
			return_code = (String) map.get("return_code");
			result_code = (String) map.get("result_code");
			err_code = (String) map.getString("err_code");
			String err_code_des = (String) map.get("err_code_des");
			if (return_code.equals("SUCCESS") && result_code.equals("SUCCESS")) {
				wLog.setState("0");
				wLog.setReturnMsg("发送成功");
				wLog.setErrCodeDes("发送成功");
				wLog.setErrCode(err_code);
				wLog.setId(map.getString("mch_billno"));
				return wLog;
			}
			if("NO_AUTH".equals(err_code)){
				wLog.setWithdrawalType(WithdrawalLog.WITHDRAWAL_TYPE_ENTERPRISE);
				map = transfers(openid,momney);
				return_code = (String) map.get("return_code");
				result_code = (String) map.get("result_code");
				err_code = (String) map.getString("err_code");
				err_code_des = (String) map.get("err_code_des");
				if (return_code.equals("SUCCESS") && result_code.equals("SUCCESS")) {
					wLog.setState("0");
					wLog.setReturnMsg("发送成功");
					wLog.setErrCodeDes("发送成功");
					wLog.setErrCode(err_code);
					wLog.setId(map.getString("mch_billno"));
					return wLog;
				}
			}
			wLog.setState("1");
			if("NOTENOUGH".equals(err_code)){
				wLog.setReturnMsg("商户余额不足");
				wLog.setErrCodeDes("商户余额不足");
			}else{
				wLog.setReturnMsg2(err_code_des);
				wLog.setErrCodeDes2(err_code_des);
			}
			wLog.setErrCode(err_code);
			wLog.setWithdrawalType(WithdrawalLog.WITHDRAWAL_TYPE_ENTERPRISE);
			wLog.setId(map.getString("mch_billno"));
			return wLog;
		} catch (Exception e) {
			log.info("transfers|openid:" + openid + ",异常:" + e.getMessage());
			wLog.setReturnMsg("发送失败,服务端异常:");
			wLog.setErrCodeDes("发送成功");
			wLog.setState("1");
			wLog.setErrCode(err_code);
			wLog.setId(CreateOrderNum.create(mchId));
			return wLog;
		}
	}
	
	/**
	 * 企业付款
	 * @param openid
	 * @param momney
	 * @throws KeyStoreException
	 * @throws NoSuchAlgorithmException
	 * @throws CertificateException
	 * @throws IOException
	 * @throws KeyManagementException
	 * @throws UnrecoverableKeyException
	 */
	protected NutMap transfers(String openid,int momney) throws Exception {
		NutMap result = NutMap.NEW();
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		FileInputStream instream = new FileInputStream(Constant.APICLIENT_CERT);
		try {
			keyStore.load(instream, mchId.toCharArray());
		} finally {
			instream.close();
		}
		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
				SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		String mch_billno = CreateOrderNum.create(mchId);// 商户订单号
		try {

			HttpPost httpget = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
			result.put("mch_appid", appId);
			result.put("mchid", mchId);
			result.put("nonce_str", GetUUID.getUUID());
			result.put("partner_trade_no", mch_billno);
			result.put("openid", openid);
			result.put("check_name", "NO_CHECK");
			result.put("amount", String.valueOf(momney));
			result.put("desc", Constant.REMARK);
			result.put("spbill_create_ip", Constant.CLIENT_IP);
			String sign = TenpayUtil.genPackageSign(TenpayUtil.toSortedMap(result), apiKey);// 签名
			result.put("sign", sign);
			String xml = Xmls.mapToXml(result);

			httpget.setEntity(new StringEntity(xml, "UTF-8"));
			CloseableHttpResponse response = httpclient.execute(httpget);
			try {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
					String text;
					String res = "";
					while ((text = bufferedReader.readLine()) != null) {
						res += text;
					}
					log.info("transfers|openid:" + openid + ",微信返回的数据:" + res);
					try {
						result = Xmls.xmlToMap(res);
					} catch (Exception e) {
						result.addv("return_code", "SUCCESS");
						result.addv("return_msg", "SUCCESS");
						result.addv("result_code", "FAIL");
						result.addv("err_code", "XML_READER_ERROR");
						result.addv("err_code_des", "解析微信结果出错");
					}
				}
				EntityUtils.consume(entity);
			} catch (Exception e) {
				result.addv("return_code", "SUCCESS");
				result.addv("return_msg", "SUCCESS");
				result.addv("result_code", "FAIL");
				result.addv("err_code", "SEND_SYSTEM_ERROR");
				result.addv("err_code_des", "发送红包出错,"+e.getMessage());
				log.info("transfers|openid:" + openid + ",异常:" + e.getMessage());
				e.printStackTrace();
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		result.addv("mch_billno", mch_billno);
		return result;
	}
	
	/**
	 * 微信红包
	 * @param openid
	 * @param momney
	 * @return
	 * @throws Exception
	 */
	protected NutMap sendredpack(String openid, int momney) throws Exception {
		NutMap result = new NutMap();
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		FileInputStream instream = new FileInputStream(new File(Constant.APICLIENT_CERT));
		try {
			keyStore.load(instream, mchId.toCharArray());
		} finally {
			instream.close();
		}
		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
				SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		CloseableHttpResponse response = null;
		String mch_billno = CreateOrderNum.create(mchId);// 商户订单号
		try {
			HttpPost post = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack");
			NutMap m = NutMap.NEW();
			String nonce_str = GetUUID.getUUID();// 32位随机字段
			m.put("nonce_str", nonce_str);
			m.put("mch_billno", mch_billno);
			m.put("mch_id", mchId);
			m.put("wxappid", appId);
			m.put("send_name", Constant.SEND_NAME);// 商户名称
			m.put("re_openid", openid);
			m.put("total_amount", String.valueOf(momney));// 付款金额 付款金额，单位分
			m.put("total_num", 1);// 红包发放总人数
			m.put("wishing", Constant.WISHING);// 红包祝福语
			m.put("client_ip", Constant.CLIENT_IP);// Ip地址
			m.put("act_name", Constant.ACT_NAME);// 活动名称
			m.put("remark", Constant.REMARK);// 备注
			String sign = TenpayUtil.genPackageSign(TenpayUtil.toSortedMap(m), apiKey);// 签名
			m.put("sign", sign);
			// System.out.println(Json.toJson(m));
			String xml = Xmls.mapToXml(m);
			post.setEntity(new StringEntity(xml, "UTF-8"));
			response = httpclient.execute(post);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
				String text;
				String res = "";
				while ((text = bufferedReader.readLine()) != null) {
					res += text;
				}
				log.info("sendredpack|openid:" + openid + ",微信返回的数据:" + res);
				try {
					result = Xmls.xmlToMap(res);
				} catch (Exception e) {
					result.addv("return_code", "SUCCESS");
					result.addv("return_msg", "SUCCESS");
					result.addv("result_code", "FAIL");
					result.addv("err_code", "XML_READER_ERROR");
					result.addv("err_code_des", "解析微信结果出错");
				}
			}
			EntityUtils.consume(entity);
		} catch (Exception e) {
			result.addv("return_code", "SUCCESS");
			result.addv("return_msg", "SUCCESS");
			result.addv("result_code", "FAIL");
			result.addv("err_code", "SEND_SYSTEM_ERROR");
			result.addv("err_code_des", "发送红包出错,"+e.getMessage());
			log.info("sendredpack|openid:" + openid + ",异常:" + e.getMessage());
			e.printStackTrace();
		} finally {
			if (null != response) {
				response.close();
			}
			httpclient.close();
		}
		result.addv("mch_billno", mch_billno);
		return result;
	}

	@Override
	public boolean checkSign(NutMap params) {
		return TenpayUtil.checkSign(params, apiKey);
	}

}
